﻿
using System.IO;
using System.Reflection;

namespace Patterns4Net.PatternEnforcer.Core
{
    using System;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Linq;
    using System.Text;
    using Patterns4Net.Core;

    /// <summary>
    /// Helper class for configuring the composition container.
    /// </summary>
    public static class CompositionContainerHelper
    {
        /// <summary>
        /// Creates the container according to the configuration.
        /// </summary>
        public static CompositionContainer GetContainer(Config.Config config, StringBuilder errors)
        {
            var pluginsCatalogs = config.GetPluginAssemblies(errors);
            pluginsCatalogs.Add(new AssemblyCatalog(typeof(PatternsLocator).Assembly)); // Patterns4Net.Core
            pluginsCatalogs.Add(new AssemblyCatalog(typeof(PatternEnforcer).Assembly)); // Patterns4.Net.PatternEnforcer.Core
            var mefCatalog = new AggregateCatalog(pluginsCatalogs);
            var container = new CompositionContainer(mefCatalog);

            // Add plugin assemblies to AttributesPatternsProvider
            var batch = new CompositionBatch();
            batch.AddExportedValue(
                "AttributesPatternsProviderAssemblies",
                pluginsCatalogs.Select(x => x.Assembly).ToArray());
            container.Compose(batch);
            return container;
        }

        public static void UpdateContainer(Config.Config config, CompositionBatch compositionBatch, StringBuilder errors)
        {
            var pluginsCatalogs = config.GetPluginAssemblies(errors);
            compositionBatch.AddPart(new AggregateCatalog(pluginsCatalogs));

            // Add plugin assemblies to AttributesPatternsProvider
            compositionBatch.AddExportedValue(
                "AttributesPatternsProviderAssemblies",
                pluginsCatalogs.Select(x => x.Assembly).ToArray());
        }

        public static PatternEnforcer GetPatternEnforcer(CompositionContainer container, StringBuilder errors)
        {
            PatternEnforcer patternEnforcer = null;
            try
            {
                patternEnforcer = container.GetExportedValue<PatternEnforcer>();
            }
            catch (Exception ex)
            {
                errors.Append("An error occurred during the composition of MEF container.");
                errors.Append("This may be caused by a bug in Patterns4Net, however it also possible that ");
                errors.Append("it was caused by user defined plugin's contracts. Make sure that all your contracts ");
                errors.Append("can be satisfied within the container and no constructor does throw any exception. ");
                errors.Append("This error is fatal and the program will be terminated. ");
                errors.AppendFormat("Detailed message: {0}", ex.Message);
                errors.AppendLine();
            }

            return patternEnforcer;
        }
    }
}
